package com.mspbots.core.script.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mspbots.core.AbstractBaseServiceImpl;
import com.mspbots.core.script.mapper.SystemScriptMapper;
import com.mspbots.core.script.mapper.TenantScriptMapper;
import com.mspbots.core.script.model.SystemScript;
import com.mspbots.core.script.model.TenantScript;
import com.mspbots.core.script.model.TenantScriptNextTicket;
import com.mspbots.core.script.service.TenantScriptService;
import com.mspbots.core.ticketai.model.TicketRule;
import com.mspbots.core.ticketai.service.TicketRuleService;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Log4j2
@Service
@RequiredArgsConstructor
public class TenantScriptServiceImpl extends AbstractBaseServiceImpl<TenantScriptMapper, TenantScript> implements TenantScriptService {

    @Autowired
    private SystemScriptMapper systemScriptMapper;

    @Autowired
    private TicketRuleService ticketRuleService;

    @Autowired
    private TenantScriptMapper tenantScriptMapper;

    @Override
    public Object updateTenantScript(String systemScript, Long tenantId) {
        List<SystemScript> systemScripts = systemScriptMapper.selectBatchIds(Arrays.asList(systemScript));
        systemScripts.forEach(item -> {
            TenantScript tenantScript = new TenantScript();
            BeanUtils.copyProperties(systemScript, tenantScript);
            tenantScript.setTenantId(tenantId);
            tenantScript.setSystemScriptId(item.getId());
            TenantScript record = getOne(new QueryWrapper<TenantScript>().eq("system_script_id", item.getId()).eq("tenant_id", tenantId));
            if (record == null) {
                save(tenantScript);
            } else {
                BeanUtils.copyProperties(systemScript, record);
                updateById(record);
            }
        });
        return true;
    }


    @Override
    public Object saveOrUpdateTenantScript(TenantScript entity) {
        if (StringUtils.isEmpty(entity.getVersion()) || entity.getVersion().equals("1.0")) {
            LocalDate date = LocalDate.now();
            String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            String versionStr = "VT." + dateStr + ".001";
            entity.setVersion(versionStr);
        } else if (entity.getVersion().startsWith("VT.")) {
            entity.setVersion(addVersionStr(entity.getVersion()));
        } else if (entity.getVersion().startsWith("VS.")) {
            entity.setVersion(entity.getVersion().replace("S", "T"));
        } else {
            LocalDate date = LocalDate.now();
            String dateStr = date.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            String versionStr = "VT." + dateStr + ".001";
            entity.setVersion(versionStr);
        }
        log.info("tenantId:" + entity.getTenantId() + ":::version :: " + entity.getVersion() + "::::name::::" + entity.getName());
        return saveOrUpdate(entity);
    }

    @Override
    public IPage<TenantScript> selectBots(Page<TenantScript> page, TenantScript query) {
        IPage<TenantScript> ipage = tenantScriptMapper.selectBots(page, query);
        if (!ObjectUtils.isEmpty(query.getSend())) {
            List<TenantScript> list = ipage.getRecords();
            list = list.stream().filter(tenantScript -> {
                if (!tenantScript.getParamsValue().isEmpty()
                        && tenantScript.getParamsValue().has("send")
                        && tenantScript.getParamsValue().get("send").asBoolean() == query.getSend()) {
                    return true;
                } else {
                    return false;
                }
            }).collect(Collectors.toList());
            page.setRecords(list);

            if (CollectionUtils.isEmpty(list)) {
                page.setTotal(0);
            } else {
                page.setTotal(list.size());
            }

        }
        return ipage;
    }


    @Override
    public Map<String, Object> getCustomScript(Long tenantId) {
        Map<String, Object> result = new HashMap<>();
        List<TenantScript> nextScripts = super.list(Wrappers.<TenantScript>lambdaQuery()
                .eq(TenantScript::getTenantId, tenantId)
                .eq(TenantScript::getScope, "NextTicket")
                .eq(TenantScript::getEnable, true));
        if (CollectionUtils.isEmpty(nextScripts)) {
            return result;
        }
        List<TenantScriptNextTicket> scriptNextTickets = nextScripts.stream().map(e -> {
            TenantScriptNextTicket b = new TenantScriptNextTicket();
            BeanUtils.copyProperties(e, b);
            return b;
        }).collect(Collectors.toList());
        result.put("script", scriptNextTickets);
        List<TicketRule> rules = ticketRuleService.getRules(tenantId, "", "CUSTOM_GRADE_POINT_RULE");
        if (CollectionUtils.isEmpty(rules)) {
            return result;
        }
        result.put("rule", rules.get(0));
        List<CustomParam> customParams = super.objectMapper.convertValue(rules.get(0).getParams(), new TypeReference<>() {
        });
        if (customParams != null) {
            scriptNextTickets.forEach(sc -> customParams.forEach(pa -> {
                if (pa.getScriptId().equals(sc.getId())) {
                    sc.setSelected(pa.isSelected());
                    sc.setPoint(pa.getPoint());
                }
            }));
        }
        return result;
    }

    @Override
    public List<TenantScript> listAndSystemInfo(TenantScript query) {
        return baseMapper.listAndSystemInfo(query);
    }

    @Override
    public Boolean closeReportAllSwitch(Long tenantId, Boolean reportSwitch) {
        Map<String, Object> map = new HashMap<>();
        map.put("tenant_id", tenantId);
        Boolean result = true;
        List<TenantScript> openBots = baseMapper.selectByMap(map);
        for (TenantScript bot : openBots) {
            Boolean flag = false;
            if (!reportSwitch) {
                flag = true;
                JsonNode param = bot.getParamsValue();
                log.info("closeReportAllSwitch:::::" + bot.getParamsValue());
                if (!ObjectUtils.isEmpty(param) && !param.asText().equals("null") && !param.asText().equals("{}")) {
                    ObjectNode paramsValObj = this.objectMapper.convertValue(bot.getParamsValue(), ObjectNode.class);
                    paramsValObj.put("send", false);
                    paramsValObj.put("sendEscalation", false);
                    bot.setParamsValue(this.objectMapper.convertValue(paramsValObj, JsonNode.class));
                }

            }
            if (!bot.getEnable().equals(reportSwitch)) {
                flag = true;
                bot.setEnable(reportSwitch);
            }
            if (flag) {
                result = result && baseMapper.updateById(bot) > 0;
            }
        }
        return result;
    }

    @Override
    public List<TenantScript> findScope() {
        return baseMapper.findScope();
    }

    @Override
    public TenantScript selectEscalation(Long tenantId) {
        Map<String, Object> map = new HashMap<>();
        map.put("tenant_id", tenantId);
        map.put("trigger_event", "Escalation");
        List<TenantScript> result = this.listByMap(map);
        if (result.size() > 0) {
            return result.get(0);
        } else {
            return null;
        }
    }

    private String addVersionStr(String oldVersion) {

        String numStr = oldVersion.substring(oldVersion.lastIndexOf(".") + 1, oldVersion.length());
        String index = Integer.parseInt(numStr) + 1 + "";
        if (index.length() < 4) {
            for (int i = 0; i < 4 - index.length(); i++) {
                index = "0" + index;
            }
        }

        String versionStr = oldVersion.substring(0, oldVersion.lastIndexOf(".") + 1) + index;

        return versionStr;
    }

    @Data
    private static class CustomParam {
        private Long scriptId;
        private String scriptName;
        private Integer point;
        private boolean selected;
    }
}
